#include "precompiled.h"
#include "itemparser.h"
using namespace weo::engine::item;
using namespace boost;
using namespace boost::filesystem;
using namespace ticpp;
using namespace std;
Itemparser::Itemparser(Itemdatabase *db)
{
    m_Itemdb = db;
    m_Armortype["Junk"] = 0;
    m_Armortype["Cloth"] = 1;
    m_Armortype["Leather"] = 2;
    m_Armortype["Mail"] = 3;
    m_Armortype["Plate"] = 4;
    m_Armortype["Shield"] = 5;
    m_Weapontype["Sword"] = 1;
    m_Weapontype["Mace"] = 2;
    m_Weapontype["Axe"] = 3;
    m_Weapontype["Fist Weapon"] = 4;
    m_Weapontype["Dagger"] = 5;
    m_Weapontype["Staff"] = 6;
    m_Weapontype["Polearm"] = 7;
    m_Weapontype["Fishing Pole"] = 8;
    m_Weapontype["Thrown"] = 9;
    m_Weapontype["Crossbow"] = 10;
    m_Weapontype["Bow"] = 11;
    m_Weapontype["Gun"] = 12;
    m_Weapontype["Wand"] = 13;
    m_Weapontype["Feral"] = 14;
    m_Weapontype["Totem"] = 15;
    m_Weapontype["Libram"] = 16;
    m_Weapontype["Idol"] = 17;
    m_SpecialMatch["damage and healing done by magical spells and effects"] = "SpellDamage";
    m_SpecialMatch["spell damage and healing"] = "SpellDamage";
    m_SpecialMatch["damage done by nature spells and effects"] = "NatureSpellDamage";
    m_SpecialMatch["damage done by fire spells and effects"] = "FireSpellDamage";
    m_SpecialMatch["damage done by frost spells and effects"] = "FrostSpellDamage"; 
    m_SpecialMatch["damage done by shadow spells and effects"] = "ShadowSpellDamage";
    m_SpecialMatch["damage done by arcane spells and effects"] = "ArcaneSpellDamage";
    m_SpecialMatch["damage done by holy spells and effects"] = "HolySpellDamage";
    m_SpecialMatch["healing spells"] = "Healing";
    m_SpecialMatch["healing done by spells and effects"] = "Healing";
    m_SpecialMatch["mana every 5 seconds"] = "MP5";
    m_SpecialMatch["mana every 5 sec"] = "MP5";
    m_SpecialMatch["mana per 5 seconds"] = "MP5";
    m_SpecialMatch["mana per 5 sec"] = "MP5";
    m_SpecialMatch["health per 5 sec"] = "HP5";
    m_SpecialMatch["healing and spell damage"] = "SpellDamage";
    m_SpecialMatch["the block value of your shield"] = "BlockValue";
    m_SpecialMatch["resilience"] = "ResilienceRating";
    m_SpecialMatch["all resistances"] = "ResistAll";
    m_SpecialMatch["melee haste rating"] = "HasteRating";
    m_IncExpression = new boost::regex("Increases\\s(?:your\\s)?(\\w+|[\\w\\s]+|damage\\sand\\shealing\\sdone\\sby\\smagical\\sspells\\sand\\seffects)\\s(?:done\\s)?by(?:\\sup\\sto)?\\s\\+?(\\d+)(?:\\sand\\sdamage\\sdone\\sby\\sup\\sto\\s(?:\\d+)\\sfor\\sall\\smagical\\sspells\\sand\\seffects)?\\s?(.*)\\.$",  boost::regex::perl|boost::regex::icase);
    m_Valuefirst = new boost::regex("^(Restores)?\\s?\\+?(\\d+)\\s([\\w\\s]*)(?:\\s\\+\\d+\\s[\\w\\s]*)?\\.?$", boost::regex::perl|boost::regex::icase);
    m_Valuelast = new boost::regex("^([\\w\\s]*)\\s\\+?(\\d+)([\\w\\s\\,]*)?\\.?$", boost::regex::perl|boost::regex::icase);
    m_KeyExpression = new boost::regex("([A-Z]{1}[a-z]+)", boost::regex::perl|boost::regex::icase);
    m_ArmorPenetration = new boost::regex("^Your\\sattacks\\signore\\s?(\\d+)\\sof\\syour\\sopponent's\\sarmor.$", boost::regex::perl|boost::regex::icase);
    m_UseTime = new boost::regex("for\\s(\\d+)\\s(?:seconds|sec)", boost::regex::perl|boost::regex::icase);
    for(unsigned int i = 0;i<weo::engine::item::KeyValuesLength;i++)
    {
        vector<string> attrsplit;
        int start = 0;
        unsigned int j = 0;
        for(j = 0;j<weo::engine::item::KeyValues[i].size();j++)
        {
            if(std::isupper(weo::engine::item::KeyValues[i][j]))
            {
                if(j != start)
                {
                    string attr = weo::engine::item::KeyValues[i].substr(start,j-start);
                    std::transform(attr.begin(), attr.end(), attr.begin(), (int(*)(int)) std::tolower);
                    attrsplit.push_back(attr);
                    start = j;
                }
            }
        }
        string attr = weo::engine::item::KeyValues[i].substr(start,j-start);
        std::transform(attr.begin(), attr.end(), attr.begin(), (int(*)(int)) std::tolower);
        attrsplit.push_back(attr);
        m_AttrSplit.push_back(attrsplit);
    }
}
std::string Itemparser::specialMatcher(string bonus)
{
    std::map<string,string>::iterator it = m_SpecialMatch.find(bonus);
    if(it != m_SpecialMatch.end()) return it->second;
    else return "None";
}
std::string Itemparser::genericPartialAttributeMatcher(string bonus)
{
    if(bonus.empty()) return "None";
    for(unsigned int i = 0;i<m_AttrSplit.size();i++)
    {
        vector<string> attrsplit = m_AttrSplit[i];
        if(attrsplit.empty()) continue;
        int pos = (int) bonus.find("strike ");
        if(pos != string::npos)
        {
            bonus.replace(pos,string("strike ").length(),"");
        }
        std::transform(bonus.begin(), bonus.end(), bonus.begin(), (int(*)(int)) std::tolower);
        tokenizer<> tok(bonus);
        vector<string> bonussplit;
        bonussplit.assign(tok.begin(),tok.end());
        if(attrsplit.size() != bonussplit.size()) continue;
        int counter = 0;
        bool* found = new bool[attrsplit.size()];
        for(unsigned int t = 0;t<attrsplit.size();t++)
        {
            found[t] = false;
        }
        for(unsigned int k = 0;k<bonussplit.size();k++)
        {
            for(unsigned int l = 0;l<attrsplit.size();l++)
            {
                if(bonussplit[k].find(attrsplit[l]) != string::npos && !found[l])
                {
                    counter++;
                    found[l] = true;
                }
            }
        }
        delete[] found;
        if (counter == attrsplit.size())
        {
            return weo::engine::item::KeyValues[i];
        }
    }
    return specialMatcher(bonus);
}
size_t Itemparser::hashString(const std::string& value) const
{
    boost::hash<std::string> string_hash;
    size_t h = string_hash(value);
    return h;
}
float Itemparser::specialValue(const std::string& value) const
{
    float floatval = ((unsigned long long) hashString(value)) % 1451147;
    cout << m_Currentfile <<" - Special Matcher: " << value << " with key: " << (unsigned int) floatval << endl;
    return floatval;
}
vector<weo::engine::item::Attribute> Itemparser::parseDescription(string desc)
{
    vector<Attribute> retval;
    boost::smatch what;
    if(regex_match(desc, what, *m_IncExpression) || regex_match(desc, what, *m_Valuefirst) || regex_match(desc, what, *m_Valuelast))
    {
        string attr = genericPartialAttributeMatcher(what[1]);
        int condindex = 3;
        if(attr == "None")
        {
            attr = genericPartialAttributeMatcher(what[3]);
            condindex = 1;
        }
        float value = boost::lexical_cast<float>(what[2]);
        if(attr != "None")
        {
            string condition = what[condindex];
            if(condition.empty())
            {
                retval.push_back(Attribute(attr,value));
            }
            else
            {
                if(condition == "in Cat, Bear, Dire Bear, and Moonkin forms only")
                {
                    retval.push_back(Attribute("FeralAP",value));
                }
                else if(condition == "Restores")
                {
                    retval.push_back(Attribute(attr,value));
                }
                else
                {
                    boost::smatch timeMatch;
                    if(regex_match(condition, timeMatch, *m_UseTime))
                    {
                        int time = boost::lexical_cast<int,std::string>(timeMatch[1]);
                        float divider = 6;
                        if(time == 15 || time == 20)
                        {
                            divider = 6; // for 15s uptime we assume 90s cooldown, for 20s uptime we assume 120s cd
                            retval.push_back(Attribute(attr,value/divider));
                        }
                    }
                }
            }
        }
        else if(what[3] == "Defense" || what[1] == "Defense")
        {
            retval.push_back(Attribute("DefenseRating",value));
        }

    }
    else
    {
        // rare cases matching here:
        if(regex_match(desc, what, *m_ArmorPenetration))
        {
            float value = boost::lexical_cast<float>(what[1]);
            retval.push_back(Attribute("ArmorPenetration",value));
        }
    }
    if(retval.empty())
    {
        retval.push_back(Attribute("Special",specialValue(desc)));
    }
    return retval;
}
// return slot,type,subtype
boost::tuple<int,int,int> Itemparser::calcTypes(int type, std::string subtype)
{ 
    // Gem: 0 gem
    // Armor: 1 head, 2 neck, 3 shoulder, 5 & 20 chest, 6 waist, 7 legs, 8 feet, 9 wrist, 10 hands, 14 Shield, 16 Cloak, 23 OffHand
    // Ring: 11
    // Trinket: 12
    // Weapon: 13 OneHand, 15 & 25 & 26 & 28 Ranged, 17 TwoHand, 21 MainHand, 22 OffHand
    // maps to:
    // Armor: None, head,neck,shoulder,cloak,chest,wrist,hands,waist,legs,feet,shield,offhand
    // Weapon: None, onehand, mainhand, offhand, twohand, ranged
    // Armortype: Junk, Cloth, Leather, Mail, Plate, Shield 
    // Weapontype: None, Sword, Mace, Axe, FistWeapon, Dagger, Staff, Polearm, FishingPole, Thrown, Crossbow, Bow, Gun, Wand, Feral, Totem, Libram, Idol 
    // Quality: Junk, Standard, Good, Rare, Epic, Legendary
    // Gem: None, Blue, Yellow, Red, Meta
    // Itemsource None = 0, Drop, Quest, Recipie, Vendor, PVP, Faction, Other };
    int subtypeint = 0;
    std::map<std::string,int>::iterator it = m_Weapontype.find(subtype);
    if(it != m_Weapontype.end()) subtypeint = it->second;
    else
    {
        it = m_Armortype.find(subtype);
        if(it != m_Armortype.end())
        {
            subtypeint = it->second;
        }
    }

    tuple<int,int,int> retval;
    switch(type)
    {
    case 0:
        retval = make_tuple(0,5,subtypeint);
        break;
    case 1:
        retval = make_tuple(1,1,subtypeint);
        break;
    case 2:
        retval = make_tuple(2,1,subtypeint);
        break;
    case 3:
        retval = make_tuple(3,1,subtypeint);
        break;
    case 5:
    case 20:
        retval = make_tuple(5,1,subtypeint);
        break;
    case 6:
        retval = make_tuple(8,1,subtypeint);
        break;
    case 7:
        retval = make_tuple(9,1,subtypeint);
        break;
    case 8:
        retval = make_tuple(10,1,subtypeint);
        break;
    case 9:
        retval = make_tuple(6,1,subtypeint);
        break;
    case 10:
        retval = make_tuple(7,1,subtypeint);
        break;
    case 14:
        retval = make_tuple(11,1,subtypeint); // shield
        break;
    case 16:
        retval = make_tuple(4,1,subtypeint);
        break;
    case 23:
        retval = make_tuple(12,1,subtypeint); // offhand
        break;
    case 11:
        retval = make_tuple(0,2,subtypeint);
        break;
    case 12:
        retval = make_tuple(0,3,subtypeint);
        break;
    case 13:
        retval = make_tuple(1,4,subtypeint);
        break;
    case 15:
    case 25:
    case 26:
    case 28:
        retval = make_tuple(5,4,subtypeint);
        break;
    case 17:
        retval = make_tuple(4,4,subtypeint);
        break;
    case 21:
        retval = make_tuple(2,4,subtypeint);
        break;
    case 22:
        retval = make_tuple(3,4,subtypeint);
        break;
    default:
        retval = make_tuple(0,0,0);
        break;
    }
    return retval;

}
void Itemparser::parseExtraFile(Item& item)
{
    string path = "D://Projekte//ItemParser//xmlitems//info//i";
    string fullfilename = path+boost::lexical_cast<string>(item.Id())+".xml";
    try
    {
        // Load a document
        Document doc( fullfilename );
        doc.LoadFile();
        Element *pParent = doc.FirstChildElement()->FirstChildElement();
        Element *pElem = pParent;
        pElem = pElem->FirstChildElement("item",false);
        if(pElem != NULL)
        {
            ticpp::Attribute* pName = pElem->FirstAttribute(false)->Next(true)->Next(true);
            if(pName != NULL)
            {
                item.setLevel(boost::lexical_cast<unsigned int>(pName->Value()));
            }
        }
        Element *pChild = pElem->FirstChildElement("containerObjects",false);
        while(pChild != NULL)
        {
            pChild = pChild->FirstChildElement("object",false);
            if(pChild != NULL)
            {
                string areaname = "";
                string creaturename = "";
                unsigned int minlevel = 0;
                ticpp::Attribute* pName = pChild->FirstAttribute(false);
                while(pName != NULL)
                {
                    if(pName->Name() == "area")
                    {
                        areaname = pName->Value();
                    }
                    else if(pName->Name() == "name")
                    {
                        creaturename = pName->Value();
                    }
                    else if(pName->Name() == "minLevel")
                    {
                        minlevel = boost::lexical_cast<unsigned int>(pName->Value());
                    }
                    pName = pName->Next(false);
                }
                if(minlevel > 60 && !areaname.empty() && creaturename.empty())
                {
                    item.setAreaname(areaname);
                    item.setCreaturename(creaturename);
                }
                pChild = pChild->NextSiblingElement("object",false);
            }
        }
        pChild = pElem->FirstChildElement("dropCreatures",false);
        while(pChild != NULL)
        {
            pChild = pChild->FirstChildElement("creature",false);
            if(pChild != NULL)
            {
                string areaname = "";
                string creaturename = "";
                unsigned int minlevel = 0;
                unsigned int classification = 0;
                ticpp::Attribute* pName = pChild->FirstAttribute(false);
                while(pName != NULL)
                {
                    if(pName->Name() == "area")
                    {
                        areaname = pName->Value();
                    }
                    else if(pName->Name() == "name")
                    {
                        creaturename = pName->Value();
                    }
                    else if(pName->Name() == "minLevel")
                    {
                        minlevel = boost::lexical_cast<unsigned int>(pName->Value());
                    }
                    else if(pName->Name() == "classification")
                    {
                        classification = boost::lexical_cast<unsigned int>(pName->Value());
                    }
                    pName = pName->Next(false);
                }
                if(classification > 0 && minlevel > 60 && !areaname.empty() && !creaturename.empty())
                {
                    item.setAreaname(areaname);
                    item.setCreaturename(creaturename);
                }
                pChild = pChild->NextSiblingElement("creature",false);
            }
        }
    }
    catch( ticpp::Exception& ex )
    {
        // If any function has an error, execution will enter here.
        // Report the error
        std::cout << ex.m_details;
    }
}
void Itemparser::parseFiles()
{
    boost::filesystem::path m_Xmlpath("D://Projekte//ItemParser//xmlitems");
    string bonusarray[] =
    {
        "bonusCritRating","bonusHitRating","bonusHasteRating",
        "bonusCritMeleeRating","bonusHitMeleeRating","bonusDodgeRating","bonusDefenseSkillRating",
        "bonusResilienceRating","bonusParryRating","bonusBlockRating",
        "bonusHitSpellRating","bonusHasteSpellRating","bonusCritSpellRating","bonusStrength",
        "bonusStamina","bonusAgility","bonusIntellect","bonusSpirit", 
        "ShadowResist", "NatureResist", "FrostResist", "FireResist", "ArcaneResist","bonusExpertiseRating"
    };
    unsigned int bonusarraylength = sizeof(bonusarray)/sizeof(string);
    if ( !exists( m_Xmlpath ) ) return;
    directory_iterator end_itr; // default construction yields past-the-end
    for ( directory_iterator itr( m_Xmlpath ); itr != end_itr; itr++ )
    {
        string filename = itr->path().leaf();
        if((filename.find(".xml") == string::npos)) continue;
        string fullfilename = itr->path().native_file_string();
        m_Currentfile = filename;
        Item newitem;
        newitem.setDPS(-1);
        newitem.setSpeed(-1);
        newitem.setUnique(false);
        newitem.setAllowed(511);
        newitem.setLevel(0);
        try
        {
            // Load a document
            Document doc( fullfilename );
            doc.LoadFile();

            // Get an element by chaining calls - no return values to check, no TiXmlHandle
            Element *pParent = doc.FirstChildElement();
            bool error = false;
            for(int i = 0;i<2;i++)
            {
                if(pParent != NULL && !pParent->NoChildren())
                {
                    pParent = pParent->FirstChildElement();
                }
                else
                {
                    error = true;
                }
            }
            if(error) continue;
            Element *pElem = pParent;
            int classid = -1;
            pElem = pElem->FirstChildElement("id",false);
            if(pElem != NULL)
            {
                newitem.setId(boost::lexical_cast<int>(pElem->GetText(false)));
            }
            pElem = pParent->FirstChildElement("name",false);
            if(pElem != NULL)
            {
                newitem.setName(pElem->GetText(false));
            }
            pElem = pParent->FirstChildElement("icon",false);
            if(pElem != NULL)
            {
                newitem.setIcon(pElem->GetText(false));
            }
            pElem = pParent->FirstChildElement("overallQualityId",false);
            if(pElem != NULL)
            {
                int qualVal = (int) pow(2.0,boost::lexical_cast<int>(pElem->GetText(false)));
                newitem.setQuality(qualVal);
            }
            if(newitem.Quality() < 2)
            {
                continue;
            }
            pElem = pParent->FirstChildElement("maxCount",false);
            if(pElem != NULL)
            {
                int value = boost::lexical_cast<int>(pElem->GetText(false));
                if(value > 0) newitem.setUnique(true);
            }
            pElem = pParent->FirstChildElement("uniqueEquippable",false);
            if(pElem != NULL)
            {
                int value = boost::lexical_cast<int>(pElem->GetText(false));
                if(value > 0) newitem.setUnique(true);
            }
            pElem = pParent->FirstChildElement("classId",false);
            if(pElem != NULL)
            {
                classid = boost::lexical_cast<int>(pElem->GetText(false));
            }
            if (!(classid == 2 || classid == 3 || classid == 4 || classid == 7)) continue;
            pElem = pParent->FirstChildElement("equipData",false);
            if(pElem != NULL)
            {
                Element *pChild = pElem->FirstChildElement("inventoryType",false);
                if(pChild != NULL)
                {
                    unsigned int invtype = boost::lexical_cast<int>(pChild->GetText(false));
                    string subclass = "";
                    pChild = pElem->FirstChildElement("subclassName",false);
                    if(pChild != NULL)
                    {
                        subclass = pChild->GetText(false);
                    }
                    tuple<int,int,int> types = calcTypes(invtype,subclass);
                    newitem.setSlot(boost::get<0>(types));
                    newitem.setType(boost::get<1>(types));
                    newitem.setSubtype(boost::get<2>(types));
                }
            }
            pElem = pParent->FirstChildElement("damageData",false);
            if(pElem != NULL)
            {
                Element *pChild = pElem->FirstChildElement("speed",false);
                if(pChild != NULL)
                {
                    newitem.setSpeed(boost::lexical_cast<float>(pChild->GetText(false)));
                }
                pChild = pElem->FirstChildElement("dps",false);
                if(pChild != NULL)
                {
                    newitem.setDPS(boost::lexical_cast<float>(pChild->GetText(false)));
                }
            }
            for(unsigned int i = 0;i<bonusarraylength;i++)
            {
                pElem = pParent->FirstChildElement(bonusarray[i],false);
                if(pElem != NULL)
                {
                    string temp = bonusarray[i];
                    temp.replace(temp.find("bonus"),string("bonus").length(),"");
                    float value = boost::lexical_cast<float>(pElem->GetText(false));
                    Attribute attr(temp,value);
                    newitem.AddAttribute(attr);
                }
            }
            pElem = pParent->FirstChildElement("spellData",false);
            if(pElem != NULL)
            {
                Element *pChild = pElem->FirstChildElement("spell",false);
                while(pChild != NULL)
                {
                    int trigger = -1;
                    string desc = "";
                    Element *pSpell = pChild->FirstChildElement("trigger",false);
                    if(pSpell != NULL)
                    {
                        trigger = boost::lexical_cast<int>(pSpell->GetText(false));
                        pSpell = pChild->FirstChildElement("desc",false);
                        if(pSpell != NULL)
                        {
                            desc = pSpell->GetText(false);
                            if(trigger == 0)
                            {
                                vector<weo::engine::item::Attribute> attrs = parseDescription(desc);
                                for(unsigned int t = 0;t<attrs.size();t++)
                                {
                                    newitem.AddAttribute(attrs[t]);
                                }
                            }
                            else if(trigger == 1)
                            {
                                vector<weo::engine::item::Attribute> attrs = parseDescription(desc);
                                for(unsigned int t = 0;t<attrs.size();t++)
                                {
                                    newitem.AddAttribute(attrs[t]);
                                }
                            }
                            else
                            {
                                newitem.AddAttribute(Attribute("Special",specialValue(desc)));
                            }
                        }
                    }
                    pChild = pChild->NextSiblingElement("spell",false);
                }
            }
            pElem = pParent->FirstChildElement("armor",false);
            if(pElem != NULL)
            {
                float value = boost::lexical_cast<float>(pElem->GetText(false));
                newitem.AddAttribute(Attribute("Armor",value));
            }
            pElem = pParent->FirstChildElement("blockValue",false);
            if(pElem != NULL)
            {
                float value = boost::lexical_cast<float>(pElem->GetText(false));
                newitem.AddAttribute(Attribute("BlockValue",value));
            }
            pElem = pParent->FirstChildElement("setData",false);
            if(pElem != NULL)
            {
                Set mySet;
                vector<string> items;
                vector<unsigned char> thresholds;
                vector<Attribute> bonus;
                vector<std::pair<unsigned char,Attribute>> combinedthreshbonus;
                Element *pChild = pElem->FirstChildElement("name",false);
                if(pChild != NULL)
                {
                    mySet.setName(pChild->GetText(false));
                    mySet.setHash(hashString(mySet.Name()));
                    pChild = pElem->FirstChildElement("item",false);
                    while(pChild != NULL)
                    {
                        ticpp::Attribute *pName = pChild->FirstAttribute(false);
                        if(pName != NULL)
                        {
                            items.push_back(pName->Value());
                        }
                        pChild = pChild->NextSiblingElement("item",false);
                    }
                    pChild = pElem->FirstChildElement("setBonus",false);
                    while(pChild != NULL)
                    {
                        ticpp::Attribute *pName = pChild->FirstAttribute(false);
                        if(pName != NULL)
                        {
                            string desc = pName->Value();
                            vector<weo::engine::item::Attribute> attrs = parseDescription(desc);
                            for(unsigned int t = 0;t<attrs.size();t++)
                            {
                                bonus.push_back(attrs[t]);
                            }
                            pName = pName->Next(false);
                            if(pName != NULL)
                            {
                                int value = boost::lexical_cast<int>(pName->Value());
                                thresholds.push_back(value);
                            }
                        }
                        pChild = pChild->NextSiblingElement("setBonus",false);
                    }
                    for(unsigned int i = 0;i<bonus.size();i++)
                    {
                        combinedthreshbonus.push_back(std::pair<unsigned char,Attribute>(thresholds[i],bonus[i]));
                    }
                }
                mySet.setItem(items);
                mySet.setBonus(combinedthreshbonus);
                newitem.setSet(mySet);
            }
            pElem = pParent->FirstChildElement("allowableClasses",false);
            if(pElem != NULL)
            {
                unsigned int allowed= 0;
                Element *pChild = pElem->FirstChildElement("class",false);
                while(pChild != NULL)
                {
                    string classname = pChild->GetText(false);
                    allowed |= weo::engine::character::Character::isAllowed(classname);
                    pChild = pChild->NextSiblingElement("class",false);
                }
                newitem.setAllowed(allowed);
            }
            pElem = pParent->FirstChildElement("socketData",false);	
            if(pElem != NULL)
            {
                unsigned int socketcount = 0;
                Sockets mySockets;
                vector<unsigned char> colors;
                vector<Attribute> bonus;
                Element* pChild = pElem->FirstChildElement("socket",false);
                while(pChild != NULL)
                {
                    ticpp::Attribute* pName = pChild->FirstAttribute(false);
                    if(pName != NULL)
                    {
                        colors.push_back(weo::engine::item::Sockets::GetColor(pName->Value()));
                    }
                    pChild = pChild->NextSiblingElement("socket",false);
                    socketcount++;
                }
                pChild = pElem->FirstChildElement("socketMatchEnchant",false);
                if(pChild != NULL)
                {
                    string desc = pChild->GetText(false);
                    vector<weo::engine::item::Attribute> attrs = parseDescription(desc);
                    for(unsigned int t = 0;t<attrs.size();t++)
                    {
                        bonus.push_back(attrs[t]);
                    }
                }
                mySockets.setCount(socketcount);
                mySockets.setColors(colors);
                mySockets.setBonus(bonus);
                newitem.setSockets(mySockets);
            }
            pElem = pParent->FirstChildElement("gemProperties",false);	
            if(pElem != NULL)
            {
                string desc = pElem->GetText(false);
                vector<string> bonussplit;
                unsigned int color = 0;
                string value[3] = {" & ", " and ", ", "};
                unsigned int lastpos = 0;

                for(unsigned int i = 0;i<3;i++)
                {
                    unsigned int pos = desc.find(value[i]);
                    if( pos != string::npos)
                    {
                        bonussplit.push_back(desc.substr(lastpos,pos-lastpos));
                        lastpos = pos+value[i].size();
                        break;
                    }
                }
                bonussplit.push_back(desc.substr(lastpos,desc.size()-lastpos));
                for(unsigned int i = 0;i<bonussplit.size();i++)
                {
                    vector<weo::engine::item::Attribute> attrs = parseDescription(bonussplit[i]);
                    for(unsigned int t = 0;t<attrs.size();t++)
                    {
                        newitem.AddAttribute(attrs[t]);
                    }
                }
                pElem = pParent->FirstChildElement("desc",false);
                if(pElem != NULL)
                {
                    desc = pElem->GetText(false);
                    tokenizer<> newtok(desc);
                    vector<string> colorsplit;
                    colorsplit.assign(newtok.begin(),newtok.end());
                    for(unsigned int i = 0;i<colorsplit.size();i++)
                    {
                        color |= weo::engine::item::Sockets::GetColor(colorsplit[i]);
                    }
                }
                newitem.setSubtype(color);
            }
            pElem = pParent->FirstChildElement("itemSource",false);
            if(pElem != NULL)
            {								
                ticpp::Attribute* pName = pElem->FirstAttribute(false);
                while(pName != NULL)
                {
                    if(pName->Name() == "value")
                    {
                        string temp = pName->Value();
                        temp.replace(temp.find("sourceType."),string("sourceType.").length(),"");
                        if(temp == "createdByPlans") newitem.setItemsource("Recipie");
                        else if(temp == "providedQuest" || temp == "questReward") newitem.setItemsource("Quest");
                        else if(temp == "vendor") newitem.setItemsource("Vendor");
                        else if(temp == "pvpReward") newitem.setItemsource("PVP");
                        else if(temp == "factionReward") newitem.setItemsource("Faction");
                        else if(temp == "creatureDrop" || temp == "worldDrop" || temp == "gameObjectDrop") newitem.setItemsource("Drop");
                        else newitem.setItemsource("Other");
                    }
                    pName = pName->Next(false);
                }
            }
            pElem = pParent->FirstChildElement("requiredSkill",false);
            if(pElem != NULL)
            {								
                ticpp::Attribute* pName = pElem->FirstAttribute(false);
                while(pName != NULL)
                {
                    if(pName->Name() == "name")
                    {
                        string temp = pName->Value();
                        newitem.setProfession(temp);
                        break;
                    }
                    pName = pName->Next(false);
                }
            }
            pElem = pParent->FirstChildElement("requiredAbility",false);
            if(pElem != NULL)
            {								
                string temp = pElem->GetText(false);
                std::string engineers[] = {"Goblin Engineer","Gnomish Engineer"};
                std::string tailoring[] = {"Spellfire Tailoring", "Shadoweave Tailoring", "Mooncloth Tailoring"};
                std::string smith[] = {"Armorsmith", "Weaponsmith", "Master Swordsmith", "Master Axesmith", "Master Hammersmith"};
                std::string leather[] = {"Dragonscale Leatherworking", "Tribal Leatherworking", "Elemental Leatherworking"};
                std::string professionNames[] = {"Engineering","Tailoring","Blacksmithing","Leatherworking"};
                std::string  *profSpecials[] = {engineers,tailoring, smith, leather};
                unsigned int profLengths[] = {2,3,5,3};
                bool found = false;
                for(int i = 0;i<sizeof(professionNames)/sizeof(std::string);i++)
                {
                    found = false;
                    std::string *profSpec = profSpecials[i];
                    for(unsigned int k = 0;k<profLengths[i];k++)
                    {
                        if(temp == profSpec[k])
                        {
                            temp = professionNames[i];
                            found = true;
                            break;
                        }
                    }
                    if(found)
                    {
                        break;
                    }
                }
                if(found)
                {
                    newitem.setProfession(temp);
                }
            }
            pElem = pParent->FirstChildElement("instanceBound",false);
            if(pElem != NULL)
            {								
                continue;
            }
            pElem = pParent->FirstChildElement("zoneBound",false);	
            if(pElem != NULL)
            {								
                continue;
            }
        }
        catch( ticpp::Exception& ex )
        {
            // If any function has an error, execution will enter here.
            // Report the error
            std::cout << ex.m_details;
            continue;
        }
        // checks if the item is ok
        // first check, gem without subtype is bad
        if(newitem.Type() == 5 && newitem.Subtype() == 0) continue;
        parseExtraFile(newitem);
        m_Itemdb->setItem(newitem);
    }
    m_Itemdb->fixAllowed();

}